package com.settlement.system.common.util.common;

import com.settlement.system.common.enums.Code;
import com.settlement.system.common.exception.ServiceAppException;
import jakarta.validation.constraints.NotNull;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.io.Serializable;
import java.util.Collection;
import java.util.Map;
import java.util.function.IntPredicate;
import java.util.function.Supplier;

import static java.lang.String.format;


/**
 *
 * 描述: 参数断言工具
 * 参考 org.springframework.util.Assert
 * @author hc
 */
@NoArgsConstructor(access=AccessLevel.PRIVATE)
public class AssertUtil {
	/**
	 * 表达式必须是true,否则抛出ServiceAppException异常
	 * @param expression 表达式
	 * @param format 异常消息模板
	 * @param args 模板参数
	 * @throws ServiceAppException if expression is false
	 */
	public static void assertTrue(boolean expression, String format,Object... args) {
		mustTrue(expression,format,args);
	}

	/**
	 * 表达式必须是false,否则抛出ServiceAppException异常
	 * @param expression 表达式
	 * @param format 异常消息模板
	 * @param args 模板参数
	 * @throws ServiceAppException if expression is true
	 */
	public static void assertFalse(boolean expression, String format,Object... args) {
		assertTrue( !expression,format(format,args) );
	}
	/**
	 * 表达式必须是true,否则抛出ServiceAppException异常
	 * @param expression 表达式
	 * @param format 异常消息模板
	 * @param args 模板参数
	 * @throws ServiceAppException if expression is false
	 */
	public static void mustTrue(boolean expression, String format,Object... args) {
		if (!expression) {
			throwServiceException(format,args);
		}
	}
	/**
	 * 表达式必须是false,否则抛出ServiceAppException异常
	 * @param expression 表达式
	 * @param format 异常消息模板
	 * @param args 模板参数
	 * @throws ServiceAppException if expression is true
	 */
	public static void mustFalse(boolean expression, String format,Object... args) {
		if (expression) {
			throwServiceException(format,args);
		}
	}
	/**
	 * Assert a boolean expression, throwing an {@code IllegalArgumentException}
	 * if the expression evaluates to {@code false}.
	 * <pre class="code">
	 * Assert.isTrue(i &gt; 0, () -&gt; "The value '" + i + "' must be greater than zero");
	 * </pre>
	 * @param expression a boolean expression
	 * @param messageSupplier a supplier for the exception message to use if the
	 * assertion fails
	 * @throws IllegalArgumentException if {@code expression} is {@code false}
	 * @since 5.0
	 */
	public static void mustTrue(boolean expression, Supplier<String> messageSupplier) {
		if (!expression) {
			throwServiceException(messageSupplier);
		}
	}
	/**
	 * 期望两个对象equals=true
	 * @param expected 期望值
	 * @param actual 实际值
	 * @param format 异常消息模板
	 * @param args 模板参数
	 * @throws ServiceAppException 对象不相等抛异常
	 */
	public static void assertEquals(@Nullable Object expected, Object actual, String format, Object... args){
		equals(expected,actual,format,args);
	}
	/**
	 * 期望两个对象equals=true
	 * @param expected 期望值
	 * @param actual 实际值
	 * @param format 异常消息模板
	 * @param args 模板参数
	 * @throws ServiceAppException 对象不相等抛异常
	 */
	public static void equals(@Nullable Object expected,Object actual, String format,Object... args){
		if(expected!=null && !expected.equals( actual )){
			throwServiceException(format,args);
		}
	}

	/**
	 * 期望两个字符串 StringUtils.equals=true
	 * @param expected 期望值
	 * @param actual 实际值
	 * @param supplier 异常消息
	 * @throws ServiceAppException 对象不相等抛异常
	 */
	public static void equals(@Nullable String expected,String actual, Supplier<String> supplier){
		if(!StringUtils.equals(expected,actual)){
			throwServiceException(supplier);
		}
	}
	/**
	 * 期望两个字符串 StringUtils.equalsIgnoreCase=true
	 * @param expected 期望字符串
	 * @param actual 实际字符串
	 * @param supplier 异常消息
	 * @throws ServiceAppException 对象不相等抛异常
	 */
	public static void equalsIgnoreCase(@Nullable String expected,String actual, Supplier<String> supplier){
		if(!StringUtils.equalsIgnoreCase(expected,actual)){
			throwServiceException(supplier);
		}
	}
	/**
	 * 期望两个字符串不想等 StringUtils.equals=false
	 * @param expected 期望值
	 * @param actual 实际值
	 * @param supplier 异常消息
	 * @throws ServiceAppException 对象不相等抛异常
	 */
	public static void notEquals(@Nullable String expected,String actual, Supplier<String> supplier){
		if(StringUtils.equals(expected,actual)){
			throwServiceException(supplier);
		}
	}
	/**
	 * 期望两个字符串不想等 StringUtils.equalsIgnoreCase=false
	 * @param expected 期望字符串
	 * @param actual 实际字符串
	 * @param supplier 异常消息
	 * @throws ServiceAppException 对象不相等抛异常
	 */
	public static void notEqualsIgnoreCase(@Nullable String expected,String actual, Supplier<String> supplier){
		if(StringUtils.equalsIgnoreCase(expected,actual)){
			throwServiceException(supplier);
		}
	}
	/**
	 * 期望两个对象equals=false,expected为null时不抛出异常
	 * @param expected 期望值
	 * @param actual 实际值
	 * @param format 异常消息模板
	 * @param args 模板参数
	 * @throws ServiceAppException 对象不相等抛异常
	 */
	public static void notEquals(@Nullable Object expected,Object actual, String format,Object... args){
		if(expected!=null && !expected.equals( actual )){
			throwServiceException(format,args);
		}
	}
	/**
	 * 期望两个code相同
	 * @param expected 期望值,枚举的代码值
	 * @param actual 实际值Code对象,枚举
	 * @param format 异常消息模板
	 * @param args 模板参数
	 * @throws ServiceAppException 对象不相等抛异常
	 */
	public static <T extends Serializable> void equals(T expected, Code<T> actual, String format, Object... args){
		if(expected==null || !expected.equals( actual.code() )){
			throwServiceException(format,args);
		}
	}

	/**
	 * 期望两个code不相同
	 * @param expected 期望值,枚举的代码值
	 * @param actual 实际值,枚举
	 * @param format 异常消息模板
	 * @param args 模板参数
	 * @throws ServiceAppException 对象不相等抛异常
	 */
	public static <T extends Serializable> void notEquals(T expected,Code<T> actual, String format,Object... args){
		if(expected!=null && expected.equals( actual.code() )){
			throwServiceException(format,args);
		}
	}
	/**
	 * object必须不是null,否则抛出异常
	 * @param object the object to check
	 * @param format 异常消息模板
	 * @param args 模板参数
	 * @throws ServiceAppException if the object is {@code null}
	 */
	public static void notNull(@Nullable Object object, @NotNull String format, @Nullable Object... args) {
		if (object == null) {
			throwServiceException(format,args);
		}
	}

	/**
	 * text必须不是空,否则抛出ServiceException异常
	 * @param text the String to check
	 * @param format 异常消息模板
	 * @param args 模板参数
	 * @throws ServiceAppException if the object is {@code null}
	 */
	public static void notBlank(String text, String format,Object... args) {
		if ( StringUtils.isBlank(text)) {
			throwServiceException(format,args);
		}
	}
	/**
	 * text必须不是空,否则抛出ServiceException异常
	 * 功能和notBlank相同,方便调用
	 * @param text the String to check
	 * @param format 异常消息模板
	 * @param args 模板参数
	 * @throws ServiceAppException if the object is {@code null}
	 */
	public static void notEmpty(String text, String format,Object... args) {
		notBlank(text,format,args);
	}
	/**
	 * text必须不是空,否则抛出ServiceException异常
	 * @param text the String to check,null或者空字符串代表长度为0
	 * @param predicate 判断长度,false的时候抛异常
	 * @param message the exception message to use if the assertion fails
	 * @throws ServiceAppException if the object is {@code null}
	 */
	public static void checkLength(String text,String message, IntPredicate predicate) {
		int length=StringUtils.isBlank(text)?0:text.length();
		assertTrue( predicate.test(length),message);
	}
	/**
	 * text必须不是空,否则抛出ServiceException异常
	 * @param text the String to check,null或者空字符串代表长度为0
	 * @param format 异常消息模板
	 * @param args 模板参数
	 * @param minInclude 最小长度,包含
	 * @param maxInclude 最大长度,包含
	 * @throws ServiceAppException if the object is {@code null}
	 */
	public static void between(String text,int minInclude,int maxInclude, String format,Object... args) {
		checkLength(text,format(format,args), i-> i>=minInclude && i<=maxInclude );
	}
	/**
	 * text必须不是空,否则抛出ServiceException异常
	 * @param num 数字
	 * @param format 异常消息模板
	 * @param args 模板参数
	 * @param minInclude 最小长度,包含
	 * @param maxInclude 最大长度,包含
	 * @throws ServiceAppException if the object is {@code null}
	 */
	public static void between(int num, int minInclude,int maxInclude, String format,Object... args) {
		assertTrue( num>=minInclude && num<=maxInclude,format(format,args));
	}
	/**
	 * text必须是空,否则抛出ServiceException异常
	 * Assert that an array has elements; that is, it must not be
	 * {@code null} and must have at least one element.
	 * <pre class="code">Assert.notEmpty(array, "The array must have elements");</pre>
	 * @param array the array to check
	 * @param format 异常消息模板
	 * @param args 模板参数
	 * @throws ServiceAppException if the object array is {@code null} or has no elements
	 */
	public static void notEmpty(Object[] array,  String format,Object... args) {
		if (ObjectUtils.isEmpty(array)) {
			throwServiceException(format,args);
		}
	}

	/**
	 * Assert that a collection has elements; that is, it must not be
	 * {@code null} and must have at least one element.
	 * <pre class="code">Assert.notEmpty(collection, "Collection must have elements");</pre>
	 * @param collection the collection to check
	 * @param format 异常消息模板
	 * @param args 模板参数
	 * @throws ServiceAppException if the collection is {@code null} or has no elements
	 */
	public static void notEmpty(Collection<?> collection, String format,Object... args) {
		if (CollectionUtils.isEmpty(collection)) {
			throwServiceException(format,args);
		}
	}

	/**
	 * Assert that a Map has entries; that is, it must not be {@code null}
	 * and must have at least one entry.
	 * <pre class="code">Assert.notEmpty(map, "Map must have entries");</pre>
	 * @param map the map to check
	 * @param format 异常消息模板
	 * @param args 模板参数
	 * @throws ServiceAppException if the map is {@code null} or has no entries
	 */
	public static void notEmpty(Map<?,?> map, String format,Object... args) {
		if (CollectionUtils.isEmpty(map)) {
			throwServiceException(format,args);
		}
	}



	/**
	 * 抛出异常
	 * @throws ServiceAppException if the map is {@code null} or has no entries
	 */
	public static void throwException( String format,Object... args) {
		throwServiceException(format,args);
	}
	/**
	 * 抛出异常
	 * @throws ServiceAppException if the map is {@code null} or has no entries
	 */
	public static void throwServiceException( String format,Object... args) {
		throw new ServiceAppException(format(format,args));
	}
	/**
	 * 抛出异常
	 * @throws ServiceAppException if the map is {@code null} or has no entries
	 */
	public static void throwServiceException(@Nullable Supplier<String> messageSupplier) {
		throw new ServiceAppException(nullSafeGet(messageSupplier));
	}

	/**
	 * 抛出异常
	 * @throws ServiceAppException if the map is {@code null} or has no entries
	 */
	public static void throwIllegalArgumentException(@Nullable Supplier<String> messageSupplier) {
		throw new IllegalArgumentException(nullSafeGet(messageSupplier));
	}

	@Nullable
	private static String nullSafeGet(@Nullable Supplier<String> messageSupplier) {
		return (messageSupplier != null ? messageSupplier.get() : null);
	}


}
